Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement integer type to comply with spec #98

Merged
merged 7 commits into from
Aug 4, 2024
Merged

Conversation

hiltontj
Copy link
Owner

@hiltontj hiltontj commented Aug 4, 2024

This PR is to address the recent CTS failure.

The JSONPath spec states that integers, e.g., those used as indices or in slice selectors, must be within a specific range [-2^53 +1, 2^53 - 1] (see here).

The CTS recently added tests to verify this behaviour in jsonpath-standard/jsonpath-compliance-test-suite#90, and serde_json_path which was not accounting for it, was failing the updated CTS.

This PR adds a new Integer type to represent such integers and check that they stay within that range. It also caught a couple of places where overflows would have led to panics.

The JSONPath spec states that integers, e.g., those used as indices or in
slice selectors, must be within a specific range [-2^53 +1, 2^53 - 1].

This adds a new Integer type to be used to represent such integers, and
check that they stay within that range. It also caught a couple of places
where overflows would have led to panics.
@hiltontj hiltontj added the compliance JSONPath Standard Compliance label Aug 4, 2024
@hiltontj hiltontj self-assigned this Aug 4, 2024
@hiltontj hiltontj marked this pull request as ready for review August 4, 2024 15:53
Integer initialization is done for small safe values, e.g., 0, 1, -1, so
this uses a panicing version of the from_i64_opt function to remove the
need for unwrap everywhere.
@hiltontj hiltontj merged commit 6c551f0 into main Aug 4, 2024
5 checks passed
@hiltontj hiltontj deleted the cts-aug-2024 branch August 4, 2024 16:42
Copy link
Contributor

@Marcono1234 Marcono1234 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed these changes, and had a short look. Hopefully my comments are useful.

///
/// This will panic if the inputted value is out of the valid range
/// [-(2<sup>53</sup>)+1, (2<sup>53</sup>)-1]).
pub fn from_i64_unchecked(value: i64) -> Self {
Copy link
Contributor

@Marcono1234 Marcono1234 Aug 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to additionally offer conversion functions (or From) for i32? i32 is probably somewhat common and can always be converted to Integer without an error.

Maybe also for u32?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Certainly, I have no issues with extending the API. Since it is public, as a result of being in core, then doing so would be useful.

Comment on lines +55 to +60
/// Take the absolute value, producing `None` if the resulting value is outside
/// the valid range [-(2<sup>53</sup>)+1, (2<sup>53</sup>)-1]).
pub fn checked_abs(mut self) -> Option<Self> {
self.0 = self.0.checked_abs()?;
self.check().then_some(self)
}
Copy link
Contributor

@Marcono1234 Marcono1234 Aug 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can this actually ever return None? The Integer limits don't permit i64::MIN so I think self.0.checked_abs() always returns Some.
And for the value range of Integer MIN.abs() == MAX, so self.check() should always be true.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great point. I think this can change to just return Self

Comment on lines +64 to +67
pub fn checked_add(mut self, rhs: Self) -> Option<Self> {
self.0 = self.0.checked_add(rhs.0)?;
self.check().then_some(self)
}
Copy link
Contributor

@Marcono1234 Marcono1234 Aug 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Out of curiosity (applies to all the mutating methods): Is this pattern of both mutating self and returning self that common (when the struct is not a 'builder')? It might be a bit error-prone, e.g. users might not expect (or notice) that self is mutated. Should instead a new Integer be returned, and self not be mutated?

Also, I am not sure if this approach of first doing self.0 = ... and then calling self.check() is safe. If the caller ignores the result, or continues to use the Integer afterwards, it now contains an invalid value.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is definitely a foot gun. I don't think it is a problem from where Integer is used in serde_json_path, but I will definitely change this.

Since these changes are not released yet I can make breaking changes to the API of Integer.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah sorry, my comment was wrong. Since it is taking mut self and not &mut self it was actually behaving as expected since Integer is Copy, and actually ended up creating a copy. But the code might still be a bit confusing then.

@hiltontj
Copy link
Owner Author

hiltontj commented Aug 4, 2024

@Marcono1234 - thanks for the comments and for calling out the quirks in the API - I will submit another PR to update the API, and may request your review.

@hiltontj hiltontj mentioned this pull request Aug 4, 2024
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
compliance JSONPath Standard Compliance
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants